module receiver #(
    parameter integer OVERSAMPLE = 16
) (
    input wire sys_clk,
    input wire rst_n,
    input wire clken,
    output reg rxclk_gen_ena,
    input wire rx,
    output reg rdy,
    input wire rdy_clr,
    output reg [7:0] data
);

  localparam integer RX_STATE_START = 2'b00;
  localparam integer RX_STATE_DATA = 2'b01;
  localparam integer RX_STATE_STOP = 2'b10;

  localparam integer OversampleWidth = $clog2(OVERSAMPLE);

  reg [1:0] state;
  reg [OversampleWidth-1:0] sample;
  reg [3:0] bitpos;
  reg [7:0] scratch;

  always @(posedge sys_clk, negedge rst_n) begin
    if (~rst_n) begin
      rdy <= 1'b0;
      data <= 8'h00;
      state <= RX_STATE_START;
      sample <= 0;
      bitpos <= 4'h0;
      scratch <= 8'h00;
      rxclk_gen_ena <= 1'b0;
    end else begin
      if (rdy_clr) rdy <= 0;

      if (~rxclk_gen_ena) begin
        if (state == RX_STATE_START && !rx) begin
          rxclk_gen_ena <= 1'b1;
        end
      end else if (clken) begin
        case (state)
          RX_STATE_START: begin
            /*
             * Start counting from the first low sample, once we've
             * sampled a full bit, start collecting data bits.
             */
            if (!rx || sample != 0) begin
              sample <= sample + 1'b1;
            end

            if (sample == (OVERSAMPLE - 1)) begin
              state   <= RX_STATE_DATA;
              bitpos  <= 0;
              sample  <= 0;
              scratch <= 0;
            end
          end
          RX_STATE_DATA: begin
            sample <= sample + 1'b1;
            if (sample == (OVERSAMPLE / 2 - 1)) begin
              scratch[bitpos[2:0]] <= rx;
              bitpos <= bitpos + 1'b1;
            end else if (sample == (OVERSAMPLE - 1)) begin
              sample <= 0;
            end
            if (bitpos == 8 && sample == (OVERSAMPLE - 1)) state <= RX_STATE_STOP;
          end
          RX_STATE_STOP: begin
            /*
           * Our baud clock may not be running at exactly the
           * same rate as the transmitter.  If we thing that
           * we're at least half way into the stop bit, allow
           * transition into handling the next start bit.
          */
            if (sample == (OVERSAMPLE - 1) || (sample >= (OVERSAMPLE / 2 - 1) && !rx)) begin
              state <= RX_STATE_START;
              data <= scratch;
              rdy <= 1'b1;
              sample <= 0;
              rxclk_gen_ena <= 1'b0;
            end else begin
              sample <= sample + 1'b1;
            end
          end
          default: begin
            state <= RX_STATE_START;
            rxclk_gen_ena <= 1'b0;
          end
        endcase
      end
    end
  end

endmodule
